﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Demos.Cons
{
    /// <summary>
    /// 线程安全Demo
    /// 采用多个线程共享同一变量的方式来演示线程加锁和加锁的情况下，计数结果的变化
    /// </summary>
    public class ThreadSafeDemo
    {
        /// <summary>
        /// 多线程计数
        /// </summary>
        /// <param name="withLock">共享变量是否加锁</param>
        public static void IncrementMultiThread(bool withLock)
        {
            int threadCount = 100;
            int incrementTimes = 10000;
            Thread[] threads = new Thread[threadCount];
            var counter = new Counter();
            for (int i = 0; i < threadCount; i++)
            {
                threads[i] = new Thread(() => Increment(counter, incrementTimes, withLock));
                threads[i].Start();
            }
            foreach (var item in threads)
            {
                item.Join();
            }
            string msg = $"线程数：{threadCount}，每个线程计数次数：{incrementTimes}";
            Console.WriteLine(msg);
            msg = withLock ? $"加锁计数结果:{threadCount} * {incrementTimes} = {counter.GetCount()}" : $"不加锁计数结果: {counter.GetCount()}";
            Console.WriteLine(msg);
        }

        /// <summary>
        /// 计数
        /// </summary>
        /// <param name="counter">计数器</param>
        /// <param name="times">计数次数</param>
        ///  /// <param name="withLock">共享变量是否加锁</param>
        private static void Increment(Counter counter, int times, bool withLock)
        {
            for (int i = 0; i < times; i++)
            {
                if (withLock)
                {
                    counter.IncrementWithLock();
                }
                else
                {
                    counter.IncrementNoLock();
                }
            }
        }
    }

    /// <summary>
    /// 计数器类
    /// 知识点：lock锁、Interlocked类
    /// </summary>
    internal class Counter
    {
        //共享变量 需要原子操作：只能同时被1个线程访问
        private int _count;
        public void IncrementWithLock()
        {
            //Interlocked原子操作，count+1；若不使用Interlocked，使用lock代替
            Interlocked.Increment(ref _count);
        }
        public void IncrementNoLock()
        {
            _count++;
        }
        public int GetCount()
        {
            return _count;
        }
    }
}
